// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: hyuan

#pragma once

#include <memory>
#include <string>
#include <unordered_map>

#include "coin2/exchange/base/order/order.h"
#include "coin2/exchange/coincheck/api_util/auth_key.h"
#include "coin2/exchange/coincheck/api_util/rate_tracker.h"
#include "coin2/exchange/order/coincheck.pb.h"

namespace coin2::exchange::coincheck::api_order {

enum CoincheckOrderSubTopicId : int { REST_ORDER_CANCEL_STATUS = 10000 };

}  // namespace coin2::exchange::coincheck::api_order

class CoincheckNativePrivateClient : public coin2::exchange::base::order::NativePrivateClient {
 public:
  using RestParams = coin2::exchange::order::CoincheckRestParams;
  using NativeClientConfig = coin2::exchange::order::OrderConnectionConfig;
  using RestQueryProto = coin2::exchange::base::order::RestQueryProto;
  using ActionType = coin2::exchange::base::order::NativePrivateClient::ActionType;
  using CoincheckRateTracker = coin2::exchange::coincheck::api_util::CoincheckRateTracker;
  using CoincheckOrderSubTopicId = coin2::exchange::coincheck::api_order::CoincheckOrderSubTopicId;

 public:
  explicit CoincheckNativePrivateClient(
      const MarketExchangeApi& mea,
      const NativeClientConfig& config);

  std::shared_ptr<AsioHttpContext> QueryAccountBalance();
  std::shared_ptr<AsioHttpContext> QueryOpenOrders();
  std::shared_ptr<AsioHttpContext> QueryFills();
  std::shared_ptr<AsioHttpContext> QueryOrderCancelStatus(const RestParams& params);

  std::shared_ptr<AsioHttpContext> PlaceOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> CancelOrder(const RestParams& params);
  std::shared_ptr<AsioHttpContext> PlaceOrderNorm(const OrderExecution&) override;
  std::shared_ptr<AsioHttpContext> CancelOrderNorm(const OrderExecution&) override;
  std::shared_ptr<AsioHttpContext> SubmitOrderExecution(const OrderExecutionProto& order) override;
  std::shared_ptr<AsioHttpContext> SubmitRestQuery(const RestQueryProto& query) override;
  void Prepare();

  RestParams GetRestOrderParams(const OrderSpec& order_spec, int64_t proc_order_id);
  RestParams GetRestCancelParams(const IOrderContext& order_context);

  std::string DebugString() const;

  BaseRestAuth* GetAuth() const override {
    auth_index_++;
    if (auth_index_ >= auths_.GetSize()) {
      auth_index_ = 0;
    }
    return auths_.GetNth(auth_index_);
  }

  const std::set<std::string>& GetCancelStatusOrderIds() { return cancel_status_order_ids_; }
  void AddCancelStatusOrderIds(const std::string& order_id) {
    if (cancel_status_order_ids_.count(order_id) > 0) {
      return;
    }
    cancel_status_order_ids_.insert(order_id);
  }
  void DelCancelStatusOrderIds(const std::string& order_id) {
    if (cancel_status_order_ids_.count(order_id) == 0) {
      return;
    }
    cancel_status_order_ids_.erase(order_id);
  }

 private:
  mutable int auth_index_{0};
  int64_t start_time_;
  CoincheckRateTracker* local_rate_tracker_;
  std::unordered_map<std::string, int32_t> api_block_info_;
  std::unordered_map<std::string, int32_t> api_req_info_;
  std::set<std::string> cancel_status_order_ids_;
};
